-- Copyright (c) 2015,2016 Lucky Byte, Inc.
--
-- Summary : POS 009.1 交易判定模块
--
-- Author  : 吴小虎 <xiaohu@lucky-byte.com>
-- Since   : 2016.4.29
--
-- History
--  * 2015.05.06 : 创建此文件
--  * 2015.08.22 : 助农取款冲正增加 subcode 属性
--

-- 每个交易有平台分配的一个代号(txx)，这个代号用于交易控制
--
-- 每个交易包含下列的属性：
--
-- code       : 平台定义的交易代码
-- subcode    : 平台定义的交易子码(可选)
-- name       : 交易名称
-- inner      : 此交易直接由平台处理，不转发到第三方
-- nomac      : 此交易没有 MAC
-- trctl      : 纳入交易控制，如果没有纳入交易控制，则允许交易
-- settl      : 清算类交易
-- reversable : 是否可冲正
-- revokable  : 是否可撤销
-- hasfee     : 此交易是否需要记手续费
--
-- 一个交易标示为 inner，通常表示这是一个定制交易，或者一个不需要转发的附加交易，
-- inner 交易通常需要和 POS 终端配对，与接出渠道没有关系
--
-- nomac、settl、reversable、revokable 属性是和 POS 标准一致的，
-- 系统可以在不同的地方利用这些信息，例如收到一笔冲正交易时，可以使用原交易的 revokable
-- 来判定原交易是否可以冲正，如果不允许，则直接拒绝终端的请求(这种情况要么是终端的错误，
-- 要么是平台与标准不一致)，注意这和交易控制没有关系
--
-- trctl 表示此交易列入交易控制，系统在收到这种交易时，会和商户配置的交易控制进行比对，
-- 如果发现商户没有配置此交易的权限，那么系统将直接拒绝终端的请求
--
-- 对于没有设置 trctl 属性的交易，系统压根就不关心其权限，这种交易系统不会阻拦
-- 通过这种方式，可以有选择的针对特定的交易进行权限控制
--
local _trcode_table = {
    -- 0800/0820 网络业务管理类消息请求
    ['0800-00-001']       = { code = 't1',  name = '签到-单倍',
        nomac = true
    },
    ['0800-00-003']       = { code = 't1',  name = '签到-双倍',
        nomac = true
    },
    ['0800-00-004']       = { code = 't1',  name = '签到-双倍-含磁道',
        nomac = true
    },
    ['0820-00-002']       = { code = 't2',  name = '签退',
        nomac = true
    },
    ['0820-00-301']       = { code = 't3',  name = '回响测试',
        nomac = true
    },
    ['0820-00-401']       = { code = 't4',  name = '收银员签到',
        nomac = true
    },
    ['0820-00-362']       = { code = 't5',  name = '状态监控',
        nomac = true
    },
    ['0800-00-360']       = { code = 't90', name = '磁条卡参数下载',
        nomac = true
    },
    ['0800-00-361']       = { code = 't91', name = '磁条卡参数下载结束',
        nomac = true
    },
    ['0800-00-364']       = { code = 't92', name = 'TMS参数下载',
        nomac = true
    },
    ['0800-00-365']       = { code = 't93', name = 'TMS参数下载结束',
        nomac = true
    },
    ['0800-00-370']       = { code = 't94', name = 'IC卡公钥下载',
        nomac = true
    },
    ['0800-00-371']       = { code = 't95', name = 'IC卡公钥下载结束',
        nomac = true
    },
    ['0820-00-372']       = { code = 't96', name = 'IC卡公钥信息查询',
        nomac = true
    },
    -- POS 009.1 2015 新增
    ['0820-00-373']       = { code = 't96', name = 'IC卡公钥信息查询-含SM2公钥',
        nomac = true
    },
    ['0800-00-380']       = { code = 't97', name = 'IC卡参数下载',
        nomac = true
    },
    ['0800-00-381']       = { code = 't98', name = 'IC卡参数下载结束',
        nomac = true
    },
    ['0820-00-382']       = { code = 't99', name = 'IC卡参数信息查询',
        nomac = true
    },
    ['0800-00-384']       = { code = 't9a', name = '币种汇率下载' },
    ['0800-00-385']       = { code = 't9b', name = '币种汇率下载结束' },
    ['0800-00-390']       = { code = 't9c', name = '卡BIN黑名单下载',
        nomac = true
    },
    ['0800-00-391']       = { code = 't9d', name = '卡BIN黑名单下载结束',
        nomac = true
    },
    ['0800-00-392']       = { code = 't9e', name = '小额取现手续费下载',
        nomac = true
    },
    ['0800-00-393']       = { code = 't9g', name = '小额取现手续费下载结束',
        nomac = true
    },

    -- 待确定
    ['0820-07-800']       = { code = 't80',  name = '电子签名上送',
        nomac = true
    },
    ['0820-07']           = { code = 't80',  name = '电子签名上送',
        nomac = true
    },

    -- 0620 基于PBOC借/贷记卡标准的IC卡脚本处理结果通知消息请求
    ['0620-00-951']       = { code = 'ta0',  name = 'IC卡脚本处理结果通知',
        nomac = true
    },

    -- 0500 对账类消息请求
    ['0500-00-201']       = { code = 't81', name = '批结算',
        nomac = true
    },

    -- 0320 批上送消息请求
    ['0320-00-201']       = { code = 't82', name = '批上送',
        nomac = true
    },
    ['0320-00-202']       = { code = 't83', name = '批上送结束不平',
        nomac = true
    },
    ['0320-00-203']       = { code = 't84', name = '上送明细-平',
        nomac = true
    },
    ['0320-00-204']       = { code = 't85', name = '上送IC卡通知信息',
        nomac = true
    },
    ['0320-00-205']       = { code = 't86', name = '上送IC卡联机交易明细',
        nomac = true
    },
    ['0320-00-206']       = { code = 't87', name = '上送IC卡通知信息不平',
        nomac = true
    },
    ['0320-00-207']       = { code = 't88', name = '批上送结束平',
        nomac = true
    },
    ['0320-00-208']       = { code = 't89', name = '上送圈存确认明细',
        nomac = true
    },
    ['0320-00-209']       = { code = 't8a', name = '上送圈存确认明细不平',
        nomac = true
    },

    -- 0220 金融通知类请求
    ['0220-200000-00-25'] = { code = 't50', name = '退货-含联盟积分' },
    ['0220-200000-00-27'] = { code = 't52', name = 'IC卡脱机交易退货' },
    ['0220-200000-08-25'] = { code = 't51', name = '订购退货' },
    ['0220-000000-00-30'] = { code = 'ttt', name = '离线结算' },
    ['0220-000000-00-32'] = { code = 'ttt', name = '结算调整' },
    ['0220-000000-00-34'] = { code = 'ttt', name = '结算调整-追加小费' },
    ['0220-000000-06-24'] = { code = 't34', name = '预授权完成-通知' },
    ['0220-630000-00-48'] = { code = 'ttt', name = '磁条卡现金充值确认' },

    -- 0200 金融类请求
    ['0200-310000-00-01'] = { code = 't10', name = '查询',
        trctl = true
    },
    ['0200-310000-65-03'] = { code = 't11', name = '联盟积分查询' },
    ['0200-000000-00-22'] = { code = 't20', name = '消费',
        trctl = true, settl = true, hasfee = true,
        reversable = true, revokable = true
    },
    ['0200-200000-00-23'] = { code = 't21', name = '消费撤销',
        trctl = true, settl = true, reversable = true
    },
    ['0200-000000-06-20'] = { code = 't32', name = '预授权完成请求',
        trctl = true, settl = true, reversable = true, revokable = true
    },
    ['0200-200000-06-21'] = { code = 't33', name = '预授权完成请求撤销',
        trctl = true, settl = true, reversable = true
    },
    ['0200-000000-18-20'] = { code = 't37', name = '订购预授权完成请求',
        trctl = true, reversable = true, revokable = true
    },
    ['0200-200000-18-21'] = { code = 't38', name = '订购预授权完成请求撤销',
        trctl = true, reversable = true
    },
    ['0200-000000-00-36'] = { code = 'ttt', name = '电子现金脱机消费' },
    ['0200-000000-64-22'] = { code = 'ttt', name = '分期付款交易',
        reversable = true, revokable = true
    },
    ['0200-200000-64-23'] = { code = 'ttt', name = '分期付款交易撤销',
        reversable = true
    },
    ['0200-000000-65-22'] = { code = 't23', name = '积分消费',
        reversable = true, revokable = true
    },
    ['0200-200000-65-23'] = { code = 't24', name = '积分消费撤销',
        reversable = true
    },
    ['0200-000000-08-22'] = { code = 't25', name = 'MOTO订购消费',
        reversable = true, revokable = true
    },
    ['0200-200000-08-23'] = { code = 't26', name = 'MOTO订购消费撤销',
        reversable = true
    },
    ['0200-600000-91-40'] = { code = 'ttt', name = 'IC卡指定账户圈存',
        reversable = true
    },
    ['0200-630000-91-41'] = { code = 'ttt', name = 'IC卡现金充值',
        reversable = true
    },
    ['0200-620000-91-42'] = { code = 'ttt', name = 'IC卡非指定账户转账圈存',
        reversable = true
    },
    ['0200-600000-91-45'] = { code = 'ttt', name = '小额支付IC卡指定账户圈存',
        reversable = true
    },
    ['0200-630000-91-46'] = { code = 'ttt', name = '小额支付IC卡现金充值',
        reversable = true
    },
    ['0200-620000-91-47'] = { code = 'ttt', name = '小额支付IC卡非指定账户圈存',
        reversable = true
    },
    ['0200-600000-00-48'] = { code = 'ttt', name = '磁条卡现金充值',
        reversable = true
    },
    ['0200-400000-66-49'] = { code = 'ttt', name = '磁条卡账户充值',
        reversable = true
    },
    ['0200-000000-67-54'] = { code = 't27', name = '预约消费',
        reversable = true, revokable = true
    },
    ['0200-200000-67-53'] = { code = 't28', name = '预约消费撤销',
        reversable = true
    },
    ['0200-170000-91-51'] = { code = 'ttt', name = '电子现金现金充值撤销',
        reversable = true
    },
    ['0200-010000-00-55'] = { code = 't60', name = '助农取款',
        trctl = true, settl = true, reversable = true
    },

    -- 0100 授权类请求
    ['0100-030000-06-10'] = { code = 't30', name = '预授权',
        trctl = true, reversable = true, revokable = true
    },
    ['0100-200000-06-11'] = { code = 't31', name = '预授权撤销',
        trctl = true, reversable = true
    },
    ['0100-330000-00-01'] = { code = 'ttt', name = '磁条卡现金充值账户验证' },
    ['0100-030000-18-10'] = { code = 't35', name = 'MOTO订购预授权',
        trctl = true, reversable = true, revokable = true
    },
    ['0100-200000-00-11'] = { code = 't36', name = 'MOTO订购预授权撤销',
        trctl = true, reversable = true
    },

    -- 0400 冲正类消息请求
    ['0400-000000-00-22'] = { code = 't22', name = '消费冲正', trctl = true },
    ['0400-200000-00-23'] = { code = 't22', name = '消费撤销冲正', trctl = true },
    ['0400-000000-06-20'] = { code = 't22', name = '预授权完成-请求冲正', trctl = true },
    ['0400-200000-06-21'] = { code = 't22', name = '预授权完成请求撤销冲正', trctl = true },
    ['0400-000000-18-20'] = { code = 't22', name = '订购预授权完成请求冲正', trctl = true },
    ['0400-200000-18-21'] = { code = 't22', name = '订购预授权完成请求撤销冲正', trctl = true },
    ['0400-000000-64-22'] = { code = 't22', name = '分期付款交易冲正', trctl = true },
    ['0400-200000-64-23'] = { code = 't22', name = '分期付款交易撤销冲正', trctl = true },
    ['0400-000000-65-22'] = { code = 't22', name = '积分消费冲正', trctl = true },
    ['0400-000000-65-22'] = { code = 't22', name = '积分消费冲正', trctl = true },
    ['0400-200000-65-23'] = { code = 't22', name = '积分消费撤销冲正', trctl = true },
    ['0400-000000-08-22'] = { code = 't22', name = 'MOTO订购消费冲正', trctl = true },
    ['0400-200000-08-23'] = { code = 't22', name = 'MOTO订购消费撤销冲正', trctl = true },
    ['0400-600000-91-40'] = { code = 't22', name = 'IC卡指定账户圈存冲正', trctl = true },
    ['0400-630000-91-41'] = { code = 't22', name = 'IC卡现金充值冲正', trctl = true },
    ['0400-620000-91-42'] = { code = 't22', name = 'IC卡非指定账户转账圈存冲正', trctl = true },
    ['0400-000000-67-54'] = { code = 't22', name = '预约消费冲正', trctl = true },
    ['0400-200000-67-53'] = { code = 't22', name = '预约消费撤销冲正', trctl = true },
    ['0400-170000-91-51'] = { code = 't22', name = '电子现金现金充值撤销冲正', trctl = true },
    ['0400-030000-06-10'] = { code = 't22', name = '预授权冲正', trctl = true },
    ['0400-200000-06-11'] = { code = 't22', name = '预授权撤销冲正', trctl = true },
    ['0400-030000-18-10'] = { code = 't22', name = 'MOTO订购预授权冲正', trctl = true },
    ['0400-200000-00-11'] = { code = 't22', name = 'MOTO订购预授权撤销冲正', trctl = true },
    ['0420-010000-00-55'] = { code = 't22', name = '助农取款冲正',
        trctl = true, subcode = '01' },

    -- 代付签到交易采用自定义消息类型 99
    ['0800-99-001']       = { code = 't1', name = '签到-单倍',
        inner = true, nomac = true
    },
    ['0800-99-003']       = { code = 't1', name = '签到-双倍',
        inner = true, nomac = true
    },
    ['0800-99-004']       = { code = 't1', name = '签到-双倍-含磁道',
        inner = true, nomac = true
    },
    ['0820-99-002']       = { code = 't2', name = '签退',
        inner = true, nomac = true
    },

    -- 消费代付采用 035.1 报文格式(定制)
    ['0200-290000-00-22'] = { code = 'tz0', name = '消费代付',
        inner = true, trctl = true, settl = false
    },
    -- 助农代付采用 035.1 报文格式(定制)
    ['0200-290000-01-55'] = { code = 'tz1', name = '助农代付',
        inner = true, trctl = true, settl = false
    },
}


-- 通过报文字段内容获取其对应的交易名称等信息
--
lib091.trinfo = function(packet)
    assert(packet._class == 'Packet091', string.format(
        'lib091.trinfo() 需要 Packet091 报文，当前报文类型为[%s]', packet._class))

    -- 不能匹配时的返回值
    local _default = {
        code = 'ttt', name = '未知交易'
    }

    local _msg_type = packet.get('1')      -- 消息类型
    if not _msg_type then
        logger.warn('报文交易类型为空，无法获取对应的交易名称.')
        return _default
    end

    local _t = {'0800', '0820', '0620', '0500', '0320'}
    if table.hasv(_t, _msg_type) then
        local _resv = packet.get('60')
        if not _resv then
            logger.error('0800/0820/0620/0500/0320 类请求缺少 60 域，请检查.')
            return _default
        end
        local _tpcode = string.sub(_resv, 1, 2)
        local _micode = string.sub(_resv, 9, 11)
        local _key
        if string.trimlen(_micode) > 0 then
            _key = string.format("%s-%s-%s", _msg_type, _tpcode, _micode)
        else
            _key = string.format("%s-%s", _msg_type, _tpcode)
        end
        return _trcode_table[_key] or _default
    end

    local _t = {'0100', '0200', '0220', '0400', '0420'}
    if table.hasv(_t, _msg_type) then
        local _proc_code = packet.get('3') or ''   -- 处理代码
        local _cond_code = packet.get('25') or ''  -- 服务点条件码
        local _resv = packet.get('60')
        if not _resv then
            notify.warn('0400/0420/0200/0220/0110 类请求缺少 60 域，请检查.')
            return _default
        end
        local _tpcode = string.sub(_resv, 1, 2)
        local _key = string.format("%s-%s-%s-%s",
            _msg_type, _proc_code, _cond_code, _tpcode)
        return _trcode_table[_key] or _default
    end

    notify.warn(string.format('未处理的消息类型[%s]', _msg_type))
    return _default
end
